Skip to content

Default theme architecture, external layer, and docs restructure - #67

Merged
minimaldesign merged 37 commits into
mainfrom
default-theme
Aug 17, 2026
Merged

Default theme architecture, external layer, and docs restructure#67
minimaldesign merged 37 commits into
mainfrom
default-theme

Conversation

@minimaldesign

@minimaldesign minimaldesign commented Aug 17, 2026

Copy link
Copy Markdown
Owner

What changed

Framework

  • Settings become the default theme (closes Restructure settings as a default theme (kill "interface tokens") #65): every design value now lives in theme.default.css (importing theme.default.tokens.css + theme.default.ui.css). The framework doesn't paint without it; consumer entries activate it right after mcss.css.
  • Theme sublayers renamed to theme.default and theme.user; theme entries pin the layer order so they slot correctly no matter how they're loaded.
  • New external layer (between theme.user and helpers): an empty slot to demote third-party CSS (@import url(vendor.css) layer(external)) so it beats the framework but loses to all project CSS. Companion patch.*.css convention for fixes to vendor styles (site's external.astro.css renamed accordingly).
  • Wireframe becomes a composed entry that imports the default theme itself and holds only its deviations; new theme.starter.css as the starting point for user themes.
  • Feedback alias tier collapsed: components use the --yes-* / --no-* / --maybe-* palettes directly.
  • Terminology: "raw tokens" + "UI tokens" everywhere; "skin" is gone.

Build & CI

  • dist/mcss.css bakes the default theme in so the drop-in stays a working single file; dist/css/mcss.css index is ordered by cascade layer with accurate per-theme comments.
  • The canonical @layer statement is derived from mcss.css at build time, and a new check-layers.mjs (pre-commit + CI) verifies every other copy (theme pins, docs code blocks, dist) agrees. --fix mode rewrites stale copies.
  • CI dist invariants updated to the new architecture (baked default theme, theme.user skins, no csstools polyfill artifacts).

Docs

  • Nav restructure, dropping the ITCSS mirror for a reader journey: Getting Started, Installation, Default HTML, Default Theme, Layout, Components, Helpers, Browser Support, AI Agents. Merged pages: default-theme (= themes + tokens), default-html (= reset + elements), layout (= global + media queries); Installation and Browser Support split out of Getting Started; new Components page hosting the marketing template.
  • All redirects consolidated in public/_redirects as real Netlify 301s (the astro.config.mjs redirects block is gone and must stay gone: its meta-refresh stubs shadow the edge rules and break .md twin fetchers). Every retired URL has a rule for both the HTML page and its .md twin.
  • Full copy rewrite of Getting Started, Default Theme, Layout, Helpers, Browser Support, and the AI rules block, with fact-check sweeps against the framework source (every documented token, class, breakpoint, and value verified).
  • Template page fix: the marketing template now imports mcss.components.css and theme.default.css (it painted nothing after the restructure).
  • Site: anchor scrolling offset for the sticky header (scroll-padding-block-start on the root).

Why

The default theme restructure makes the framework/theme boundary real: structure ships in layers, every design value lives in one swappable place, and user themes override it predictably. The docs restructure retires the file-taxonomy nav for pages organized around what a reader is trying to do.

Reviewer notes

  • Breaking relative to v1.3.0: layer names, theme file names, and docs URLs all changed. Old docs URLs 301 via _redirects; framework consumers need the new theme activation line.
  • Post-deploy check owed: curl the retired URLs (both HTML and .md forms) on the live site to confirm Netlify serves real 301s; _redirects is new and can't be fully verified locally.
  • check-layers.mjs is the guard against the layer statement drifting between its (deliberately) duplicated copies; run npm run check:layers -- --fix after any layer change.

Closes #65

minimaldesign and others added 30 commits August 14, 2026 16:47
settings.tokens.css and settings.ui.css move to
theme.default.tokens.css and theme.default.ui.css, each self-layered
into the new theme.defaults sublayer, with a theme.default.css entry
importing both. mcss.css drops the settings layer and imports, and
declares theme.defaults + theme.overrides in the layer order; user
themes land in theme.overrides so they beat the default regardless of
import order. The site entry (_global.css) activates the default theme
explicitly. mcss.css alone no longer paints a page: the default theme
carries every design value.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
theme.wireframe.css now imports the default theme and lands its own
overrides in theme.overrides, making it a self-contained swappable
skin: activate it INSTEAD of theme.default.css. The marketing
template's pinned layer statement follows the new order. The old empty
theme.default.css template role moves to theme.starter.css, pre-wrapped
in theme.overrides with the same guidelines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A composed brand gradient is site content, not a scale step. The
marketing template's hero inlines it; the token is gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dist/mcss.css and dist/mcss.min.css now bundle theme.default.css so the
one-file drop-in keeps painting a complete default look. The dist/css
index activates the default theme import (the framework doesn't paint
without one), marks its two parts as imported by the entry, and leaves
other theme entries commented for swapping. Layer statement and prefix
map drop the retired settings layer; the theme.default.css per-file
output passes through untouched (imports only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… tokens

Every reference to settings.tokens.css / settings.ui.css follows the
files into theme.default.*; the term interface tokens dies in favor of
ui tokens everywhere (docs pages, component pages, agents docs,
CLAUDE.md, blog structure post's kept-current list, homepage copy,
llms.txt pointer). start.mdx, themes.mdx, tokens.mdx, and ai.mdx teach
the new model: the framework is structure plus a default theme you
activate and never edit; your theme overrides it from theme.overrides
regardless of import order; the ownership rule now has no exceptions
(the edit-tokens-at-setup guidance is gone). The AI rules block and
skill mirror are synced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Layer priority is set by first declaration, so a theme file parsed
before mcss.css used to establish the wrong order (theme before base).
theme.default.css, theme.starter.css, and theme.wireframe.css now open
with the canonical @layer statement, the same trick the marketing
template uses inline: whichever framework file loads first pins the
correct order, and a user override loaded before the framework still
wins. Verified in-browser: override-before-framework wins, wireframe
skin renders over the composed default, dist/mcss.min.css alone paints
the complete default look.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The parts aren't standalone themes, they're internal files with one
blessed loader, so theme.default.css assigns layer(theme.defaults) on
its imports the same way mcss.css layers the structural files, and the
part files go back to flat, unwrapped CSS. Only standalone theme files
(starter, skins) still self-layer. The dist build pre-wraps the dist
copies of the parts so a lone <link> on one still slots correctly.
agents/css.md and CLAUDE.md state the refined convention: files a
consumer loads directly self-layer; files an entry imports are layered
by the entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
theme.defaults becomes theme.default, so the layer name matches the
theme.default.* file prefix exactly instead of differing by a plural.
theme.overrides becomes theme.user: overrides was redundant (every
later layer overrides earlier ones); user names whose slot it is and
pairs naturally with default. (default is safe as a layer name: the
reservation applies to custom-ident contexts, and layer names take
plain idents; verified parsing in-browser.) Swept across the framework,
build script, marketing template pin, docs, blog note, and the AI
block + skill mirror.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The --success/danger/warning-* aliases over --yes/no/maybe-* were a
synonym layer: the raw palettes are already semantically named, and
adoption was split (notices and button variants consumed the raw
scales), so overriding an alias silently missed half the feedback
surfaces. Everything now consumes the palettes directly, the fifteen
alias declarations are gone, and the docs plus AI block and skill
mirror state the single-vocabulary rule. Component token names like
--badge-success-color keep their variant names; only their values
changed. Computed values are identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"The import below brings in every default" read as if the defaults
were in this file; say instead that the file contains only the skin's
deviations and the @import makes the browser load theme.default.css
alongside it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add an explicit npm run check:layers step and tighten dist verification. Replace fragile layer greps with checks that detect cascade-layers/light-dark polyfill artifacts and csstools output, require the default theme to be baked into dist/mcss.css, and ensure components and user themes are only present in their own bundles. Also validate standalone theme files self-layer as theme.user and prevent unresolved custom-media/mixin syntax from shipping.
The marketing template imported only mcss.css, which since the default
theme restructure carries no design values (nothing paints without
theme.default.css) and no component styles either. Import both alongside
it, the same way any consumer entry does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove several redundant preview/dev entries, normalize runtimeArgs formatting, and replace the old dev-4340 entry with a single preview configuration on port 4400. Keeps the existing dev entry on port 4321.
@netlify

netlify Bot commented Aug 17, 2026

Copy link
Copy Markdown

Deploy Preview for mcssdev ready!

Name Link
🔨 Latest commit 6f5e7d0
🔍 Latest deploy log https://app.netlify.com/projects/mcssdev/deploys/6a828fe0054c710008ea5b76
😎 Deploy Preview https://deploy-preview-67--mcssdev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 100
Accessibility: 98
Best Practices: 100
SEO: 97
PWA: 70
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@minimaldesign

Copy link
Copy Markdown
Owner Author

Redirect verification: done (against the Netlify deploy preview), closing out the "post-deploy check owed" item from the PR description.

All 18 retired/legacy URLs return real edge 301s with correct targets:

  • Every merged docs page and its .md twin (/docs/tokens{,.md}, /docs/themes{,.md}, /docs/reset{,.md}, /docs/elements{,.md}, /docs/global{,.md}, /docs/media-queries{,.md}) → default-theme / default-html / layout (+ .md)
  • /docs/template and /components/template/docs/components#marketing-template (anchor survives); /docs/template.md/docs/components.md
  • Legacy rules migrated from astro.config: /components/ReadProgressBar → lowercase page, /tags and /tags/* splat → /blog/tags/...
  • A followed .md redirect serves actual markdown (# Default Theme), not an HTML stub — the failure mode that motivated moving redirects to _redirects
  • No case-collision loop: /components/readprogressbar serves the page (its lone 301 is Netlify's trailing-slash normalization, 200 in one hop)

🤖 Verified by Claude Code

@minimaldesign
minimaldesign merged commit b6ebe9f into main Aug 17, 2026
5 checks passed
@minimaldesign
minimaldesign deleted the default-theme branch August 17, 2026 04:39
minimaldesign added a commit that referenced this pull request Aug 17, 2026
The 1.4.0 bump landed on default-theme after #67 was already merged;
this brings it to main. 1.4.0 rather than 2.0.0 because versions here
mark copyable states of the repo, not an API contract, and 1.2.0/1.3.0
already shipped breaking changes as minors with a Breaking changelog
section.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restructure settings as a default theme (kill "interface tokens")

1 participant